As described herein, a run-time environment is typically one in which an application server or virtual machine executes on a computer processing device, computer, or machine. Examples of such run-time environments include Sun's Java Virtual Machine from Sun Microsystems, Inc. and the JRockit Virtual Machine from Bea Systems, Inc. Typically the run-time environment, often referred to as a virtual machine (VM) executes upon an application server operating system, and provides access to a plurality of clients such as Java clients, that wish to run applications at the server. The system is generally thread-based in that requests for processing at the server execute in threads and are handled by the server within these threads. However, problems may arise if the threads are stopped in an unstable (or more correctly termed “unsafe”) state. The term “run-time system” may suggest that threads are continuously running or executing. However, there are many instances, some of which are described in further detail below, in which the threads must be stopped in order to perform some particular operation. When the threads are stopped in this manner problems may arise unless the threads are stopped in a safe state.
Among the circumstances that require the threads to be stopped in order to perform operations, the following are perhaps of most importance.    1. Garbage collection. Most run-time environments, including the Java Virtual Machine and the JRockit Virtual Machine support some form of garbage collection. This is a process in which objects that are no longer in use by the run-time environment are deleted or cleared, to free up resources for use by other objects. A typical garbage collection process requires each thread to report which objects associated with that thread are still in use or “alive”. The usual approach to this is to create a “live map” or a garbage collection map for each thread which identifies the live objects. However, in order to create the live map or garbage collection map the thread must be stopped in a safe state, and preferably on an instruction that contains a live object.    2. Context switching. Depending on the run-time environment or the virtual machine being used, context switching may be performed within the threads. Preemptive switching from one thread to another is not always allowed, and depending on the run-time environment may not be recommended. In any case context switching is only allowed on a safe state instruction. This requires the threads to be stopped in a safe state prior to context switching. Some vendors have tried to work around this problem by incorporating a state flag within each thread. For example, operating systems such as Solaris and Linux use a state flag to indicate whether the thread is in a non-switchable state. If the state flag indicates the thread is in a non-switchable state the system resumes thread execution and retries again at a later point in time.    3. Thread locking on a single CPU machine. This factor is an extension of the context switching feature described above. When using a single processor machine (i.e., using a single thread to run all of the code), care must be taken to ensure that preemptive thread switching is not performed within lock regions.
The traditional approach to the problem of stopping the threads in a safe states is to select one of three strategies. First, the system can attempt to make all states safe prior to stopping them. This is not always possible depending on the specific situation. This approach is also very costly memory-wise to implement.
An alternative approach is to poll the threads, i.e., to stop, then restart the thread, and stop it again a little later in time, until it is eventually stopped in a safe state. The problem with this approach is that it is cumbersome and involves numerous thread context switching. Furthermore, the polling approach is not even guaranteed to terminate since it starts and stops threads randomly and will only complete if it stops in a safe state, which potentially may never happen (although will typically just take a long time to happen).
The third approach is to determine if a thread is stopped in an unsafe state, and if it is determined as such then the system inserts a stop-point at a safe-state point, restarts the thread, and lets it run until it reaches the stop-point. This code patching approach is also very cumbersome and time-consuming to use, and requires numerous thread context switches.